<!DOCTYPE html><html class="theme-next pisces use-motion" lang="zh-Hans"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta name="theme-color" content="#222"><meta name="baidu-site-verification" content="YdMoGbLGAx"><script src="/lib/pace/pace.min.js?v=1.0.2"></script><link href="/lib/pace/pace-theme-minimal.min.css?v=1.0.2" rel="stylesheet"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><meta name="google-site-verification" content="L2XxDS_YgUmo9ng6ga0rnR1w_IcqBAut-k_te_C1TCQ"><link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css"><link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.ico?v=5.1.4"><link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.ico?v=5.1.4"><meta name="keywords" content="Java, Spring, Spring boot, Machine learning, Deep learning"><meta name="description" content="近期一直在面试，对面试中的内容做一些总结。"><meta property="og:type" content="article"><meta property="og:title" content="面试总结"><meta property="og:url" content="http://gtwlover.gitee.io/2017/05/25/面试总结/index.html"><meta property="og:site_name" content="Better Man"><meta property="og:description" content="近期一直在面试，对面试中的内容做一些总结。"><meta property="og:image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/Spring%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E7%BA%A7%E5%88%AB.png"><meta property="og:image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/SpringFramework.png"><meta property="og:updated_time" content="2018-02-12T12:27:24.000Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="面试总结"><meta name="twitter:description" content="近期一直在面试，对面试中的内容做一些总结。"><meta name="twitter:image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/Spring%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E7%BA%A7%E5%88%AB.png"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",scheme:"Pisces",version:"5.1.4",sidebar:{position:"left",display:"post",offset:12,b2t:!1,scrollpercent:!0,onmobile:!1},fancybox:!0,tabs:!0,motion:{enable:!0,async:!1,transition:{post_block:"fadeIn",post_header:"slideDownIn",post_body:"slideDownIn",coll_header:"slideLeftIn",sidebar:"slideUpIn"}},duoshuo:{userId:"gtwlover",author:"博主"},algolia:{applicationID:"GOSX1252HP",apiKey:"eefb124f52fc415c356384bb0ed50bda",indexName:"myblog",hits:{per_page:10},labels:{input_placeholder:"请输入要查找的关键字",hits_empty:"未找到 ${query} 相关结果",hits_stats:"${hits} 条相关条目，使用了 ${time} 毫秒"}}}</script><link rel="canonical" href="http://gtwlover.gitee.io/2017/05/25/面试总结/"><title>面试总结 | Better Man</title><script>!function(e,a,t,n,g,c,o){e.GoogleAnalyticsObject=g,e.ga=e.ga||function(){(e.ga.q=e.ga.q||[]).push(arguments)},e.ga.l=1*new Date,c=a.createElement(t),o=a.getElementsByTagName(t)[0],c.async=1,c.src="https://www.google-analytics.com/analytics.js",o.parentNode.insertBefore(c,o)}(window,document,"script",0,"ga"),ga("create","UA-97111795-1","auto"),ga("send","pageview")</script></head><body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans"><div class="container sidebar-position-left page-post-detail"><div class="headband"></div> <a href="https://github.com/gaotingwang"><img style="position:absolute;top:0;right:0;border:0" src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"></a><header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader"><div class="header-inner"><div class="site-brand-wrapper"><div class="site-meta"><div class="custom-logo-site-title"><a href="/" class="brand" rel="start"><span class="logo-line-before"><i></i></span> <span class="site-title">Better Man</span><span class="logo-line-after"><i></i></span></a></div><p class="site-subtitle">时间以北慕城南，故人以北爱荒凉</p></div><div class="site-nav-toggle"> <button><span class="btn-bar"></span><span class="btn-bar"></span><span class="btn-bar"></span></button></div></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-home"><a href="/" rel="section"><i class="menu-item-icon fa fa-fw fa-home"></i><br> 首页</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section"><i class="menu-item-icon fa fa-fw fa-archive"></i><br> 归档</a></li><li class="menu-item menu-item-search"><a href="javascript:;" class="popup-trigger"><i class="menu-item-icon fa fa-search fa-fw"></i><br> 搜索</a></li></ul><div class="site-search"><div class="algolia-popup popup search-popup"><div class="algolia-search"><div class="algolia-search-input-icon"><i class="fa fa-search"></i></div><div class="algolia-search-input" id="algolia-search-input"></div></div><div class="algolia-results"><div id="algolia-stats"></div><div id="algolia-hits"></div><div id="algolia-pagination" class="algolia-pagination"></div></div><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span></div></div></nav></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><div class="post-block"><link itemprop="mainEntityOfPage" href="http://gtwlover.gitee.io/2017/05/25/面试总结/"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="脱毛大白兔"><meta itemprop="description" content=""><meta itemprop="image" content="http://gtw.oss-cn-shanghai.aliyuncs.com/myself/my3.jpeg?x-oss-process=style/zoom"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="Better Man"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">面试总结</h1><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i></span> <span class="post-meta-item-text">发表于</span> <time title="创建于" itemprop="dateCreated datePublished" datetime="2017-05-25T17:58:01+08:00">2017-05-25</time></span> <span class="post-comments-count"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-comment-o"></i></span><a href="/2017/05/25/面试总结/#comments" itemprop="discussionUrl"><span class="post-comments-count gitment-comments-count" data-xid="/2017/05/25/面试总结/" itemprop="commentsCount"></span></a></span> <span id="/2017/05/25/面试总结/" class="leancloud_visitors" data-flag-title="面试总结"><span class="post-meta-divider">|</span><span class="post-meta-item-icon"><i class="fa fa-eye"></i></span> <span class="post-meta-item-text">阅读次数&#58;</span><span class="leancloud-visitors-count"></span></span><div class="post-description"> 近期一直在面试，对面试中的内容做一些总结。</div></div></header><div class="post-body" itemprop="articleBody"><h2 id="Java相关"><a href="#Java相关" class="headerlink" title="Java相关"></a>Java相关</h2><h3 id="Java基础"><a href="#Java基础" class="headerlink" title="Java基础"></a>Java基础</h3><ul><li><p>字符串</p><p>关于字符串拼接问题，可以参考之前博客<a href="http://gtwlover.gitee.io/2017/04/10/Java%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8B%BC%E6%8E%A5%E6%95%88%E7%8E%87%E5%88%86%E6%9E%90/">Java字符串拼接效率分析</a>。</p><p>需要注意String在Java中是final的，是<strong>不可变对象</strong>，对String做的任何修改操作都是产生新的对象，不是对原有对象的修改，对原对象不会产生影响，如：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// Java String API</span></div><div class="line"><span class="function"><span class="keyword">public</span> String <span class="title">concat</span><span class="params">(String str)</span> </span>&#123;</div><div class="line">  <span class="keyword">int</span> otherLen = str.length();</div><div class="line">  <span class="keyword">if</span> (otherLen == <span class="number">0</span>) &#123;</div><div class="line">    <span class="keyword">return</span> <span class="keyword">this</span>;</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">int</span> len = value.length;</div><div class="line">  <span class="keyword">char</span> buf[] = Arrays.copyOf(value, len + otherLen);</div><div class="line">  str.getChars(buf, len);</div><div class="line">  </div><div class="line">  <span class="comment">//注意此处是new</span></div><div class="line">  <span class="keyword">return</span> <span class="keyword">new</span> String(buf, <span class="keyword">true</span>);</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>String会有常量池，字符串已存在，会直接从常量池中获取，如果没有，则创建后会放入常量池。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div></pre></td><td class="code"><pre><div class="line">String s1 = <span class="string">"abc"</span>;</div><div class="line">String s2 = <span class="string">"abc"</span>; <span class="comment">// 为常量池中对象</span></div><div class="line">String s3 = <span class="string">"a"</span> + <span class="string">"bc"</span>; <span class="comment">// Java中有常量优化机制,在编译时期就能确定s2的值为"abc",所以编译时期,在常量池中创建"abc"</span></div><div class="line"></div><div class="line">System.out.println(s1 == s2); <span class="comment">// true</span></div><div class="line">System.out.println(s2 == s3); <span class="comment">// true</span></div><div class="line"></div><div class="line">String s1 = <span class="string">"ab"</span>;</div><div class="line">String s2 = <span class="string">"abc"</span>;</div><div class="line">String s3 = s1 + <span class="string">"c"</span>;  <span class="comment">//s1是变量,引用的值在程序编译期是无法确定的</span></div><div class="line">System.out.println(s3 == s2); <span class="comment">//false</span></div><div class="line"><span class="comment">// 对于final修饰的变量，它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。</span></div><div class="line"><span class="keyword">final</span> String h = <span class="string">"a"</span>;</div><div class="line">String s4 = h + <span class="string">"bc"</span>;</div><div class="line">System.out.println(s4 == s2);</div><div class="line">    </div><div class="line"><span class="comment">//创建几个对象</span></div><div class="line"><span class="comment">//创建一个或两个对象,取决于之前常量池中是否有此常量，一个在常量池中,一个在堆内存中</span></div><div class="line">String s1 = <span class="keyword">new</span> String(<span class="string">"abc"</span>);        </div><div class="line">System.out.println(s1);</div></pre></td></tr></table></figure></li><li><p>基本类型</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/*</span></div><div class="line"> * -128到127是byte的取值范围,如果在这个取值范围内,自动装箱就不会新创建对象,而是从常量池中获取</div><div class="line"> * 如果超过了byte取值范围就会再新创建对象</div><div class="line"> */</div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Integer <span class="title">valueOf</span><span class="params">(<span class="keyword">int</span> i)</span> </span>&#123;</div><div class="line">    <span class="keyword">assert</span> IntegerCache.high &gt;= <span class="number">127</span>;</div><div class="line">    <span class="keyword">if</span> (i &gt;= IntegerCache.low &amp;&amp; i &lt;= IntegerCache.high)            <span class="comment">//i&gt;= -128 &amp;&amp; i &lt;= 127</span></div><div class="line">        <span class="keyword">return</span> IntegerCache.cache[i + (-IntegerCache.low)];</div><div class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Integer(i);</div><div class="line">&#125;</div></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div></pre></td><td class="code"><pre><div class="line">Integer i5 = <span class="number">97</span>;</div><div class="line">Integer i6 = <span class="number">97</span>;</div><div class="line">System.out.println(i5 == i6);</div><div class="line">System.out.println(<span class="string">"-----------"</span>);        <span class="comment">//true</span></div><div class="line"></div><div class="line">Integer i7 = <span class="number">197</span>;</div><div class="line">Integer i8 = <span class="number">197</span>;</div><div class="line">System.out.println(i7 == i8);            <span class="comment">//false</span></div><div class="line"></div><div class="line"><span class="keyword">short</span> s1 = <span class="number">1</span>;</div><div class="line"><span class="comment">// s1+1运算时会自动提升表达式的类型，所以结果是int型，再赋值给short类型s1时，编译器将报告需要强制转换类型的错误。</span></div><div class="line">s1 = s1 + <span class="number">1</span>;</div><div class="line"></div><div class="line"><span class="keyword">short</span> s2 = <span class="number">1</span>;</div><div class="line"><span class="comment">//  += 是java语言规定的运算符，java编译器会对它进行特殊处理，因此可以正确编译</span></div><div class="line">s2 += <span class="number">1</span>;</div></pre></td></tr></table></figure></li><li><p>finally</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// catch中的return在finally之后执行 但是会将return的值放到一个地方存起来，所以finally中的ret=2会执行，但返回值是1。</span></div><div class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</div><div class="line"><span class="keyword">try</span>&#123;</div><div class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> Exception();</div><div class="line">&#125;<span class="keyword">catch</span>(Exception e)&#123;</div><div class="line">    ret = <span class="number">1</span>;</div><div class="line">    <span class="keyword">return</span> ret;</div><div class="line">&#125;<span class="keyword">finally</span>&#123;</div><div class="line">    ret = <span class="number">2</span>;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// finally中有return值，则返回的是return的值，此处则是2</span></div><div class="line"><span class="keyword">int</span> ret = <span class="number">0</span>;</div><div class="line"><span class="keyword">try</span>&#123;</div><div class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> Exception();</div><div class="line">&#125;<span class="keyword">catch</span>(Exception e)&#123;</div><div class="line">    ret = <span class="number">1</span>;</div><div class="line">    <span class="keyword">return</span> ret;</div><div class="line">&#125;<span class="keyword">finally</span>&#123;</div><div class="line">    ret = <span class="number">2</span>;</div><div class="line">    <span class="keyword">return</span> ret;</div><div class="line">&#125;</div></pre></td></tr></table></figure></li></ul><h3 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h3><p>线程相关知识点参考之前博客<a href="http://gtwlover.gitee.io/2016/12/10/Thread%E7%9F%A5%E8%AF%86%E7%82%B9/">Thread知识点</a>。常见面试题：</p><ol><li><p>Java中堆和栈有什么不同</p><p>为什么把这个问题归类在多线程和并发面试题里？因为栈是一块和线程紧密相关的内存区域。<strong>每个线程都有自己的栈内存，用于存储本地变量，方法参数和栈调用</strong>，一个线程中存储的变量对其它线程是不可见的。而<strong>堆是所有线程共享的一片公用内存区域。对象都在堆里创建</strong>，为了提升效率线程会从堆中弄一个缓存到自己的栈，如果多个线程使用该变量就可能引发问题，这时volatile 变量就可以发挥作用了，它要求线程从主存中读取变量的值。</p></li><li><p>什么是线程？线程和进程区别</p><p>线程是操作系统能够进行运算调度的最小单位，它被包含在进程之中，是进程中的实际运作单位。程序员可以通过它进行多处理器编程，你可以使用多线程对运算密集型任务提速。<strong>线程是进程的子集</strong>，一个进程可以有很多线程，每条线程并行执行不同的任务。<strong>不同的进程使用不同的内存空间，而所有的线程共享一片相同的内存空间</strong>。别把它和栈内存搞混，每个线程都拥有单独的栈内存用来存储本地数据。</p></li><li><p>Java中Runnable和Callable有什么不同</p><p>Runnable和Callable都代表那些要在不同的线程中执行的任务。Runnable从JDK1.0开始就有了，Callable是在JDK1.5增加的。它们的主要区别是Callable的 call() 方法可以返回值和抛出异常，而Runnable的run()方法没有这些功能。Callable可以返回装载有计算结果的Future对象。</p></li><li><p>Java中CyclicBarrier 和 CountDownLatch有什么不同</p><p>CyclicBarrier 和 CountDownLatch 都可以用来让一组线程等待其它线程。与 CyclicBarrier 不同的是，CountdownLatch 不能重新使用。</p></li><li><p>Java中的volatile 变量</p><p>volatile是一个特殊的修饰符，只有成员变量才能使用它。在Java并发程序缺少同步类的情况下，多线程对成员变量的操作对其它线程是透明的。<strong>volatile变量可以保证下一个读取操作会在前一个写操作之后发生</strong></p></li><li><p>什么是线程安全</p><p>有多个线程在同时运行，而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的，而且其他的变量的值也和预期的是一样的，就是线程安全的。eg:Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的</p></li><li><p>Java中如何停止一个线程</p><p>Java提供了很丰富的API但没有为停止线程提供API。JDK 1.0本来有一些像stop(), suspend() 和 resume()的控制方法但是由于潜在的死锁威胁因此在后续的JDK版本中他们被弃用了，之后Java API的设计者就没有提供一个兼容且线程安全的方法来停止一个线程。当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程，你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程。或遇到未捕获的异常。</p></li><li><p>一个线程运行时发生异常会怎样</p><p>如果异常没有被捕获该线程将会停止执行。Thread.UncaughtExceptionHandler是用于处理未捕获异常造成线程突然中断情况的一个内嵌接口。当一个未捕获异常将造成线程中断的时候JVM会使用Thread.getUncaughtExceptionHandler()来查询线程的UncaughtExceptionHandler并将线程和异常作为参数传递给handler的uncaughtException()方法进行处理</p></li><li><p>如何在两个线程间共享数据</p><p>使用同步对象(使用Lock、synchronized)、使用阻塞队列BlockQueue</p></li><li><p>Java中notify 和 notifyAll有什么区别</p><p>notify()方法不能唤醒某个具体的线程，所以只有一个线程在等待的时候它才有用武之地。而notifyAll()唤醒所有线程并允许他们争夺锁确保了至少有一个线程能继续运行。</p></li><li><p>为什么wait, notify 和 notifyAll这些方法不在thread类里面</p><p><strong>JAVA提供的锁是对象级的而不是线程级的，每个对象都有锁，通过线程获得</strong>。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中，线程正在等待的是哪个锁就不明显了。简单的说，<strong>由于wait，notify和notifyAll都是锁级别的操作，所以把他们定义在Object类中因为锁属于对象。</strong></p></li><li><p>什么是ThreadLocal变量</p><p>ThreadLocal是Java里一种特殊的变量<strong>。每个线程都有一个ThreadLocal就是每个线程都拥有了自己独立的一个变量</strong>，竞争条件被彻底消除了。它是为创建代价高昂的对象获取线程安全的好方法，比如你可以用ThreadLocal让SimpleDateFormat变成线程安全的，因为那个类创建代价高昂且每次调用都需要创建不同的实例所以不值得在局部范围使用它，如果为每个线程提供一个自己独有的变量拷贝，将大大提高效率。首先，通过复用减少了代价高昂的对象的创建个数。其次，你在没有使用高代价的同步或者不变性的情况下获得了线程安全。线程局部变量的另一个不错的例子是ThreadLocalRandom类，它在多线程环境中减少了创建代价高昂的Random对象的个数。</p></li><li><p>什么是FutureTask</p><p>在Java并发程序中FutureTask表示一个<strong>可以取消的异步运算</strong>。它有<strong>启动和取消运算、查询运算是否完成和取回运算结果等方法</strong>。只有当运算完成的时候结果才能取回，如果运算尚未完成get方法将会阻塞。一个FutureTask对象可以对调用了Callable和Runnable的对象进行包装，由于FutureTask也是调用了Runnable接口所以它可以提交给Executor来执行。</p></li><li><p>Java中interrupted 和 isInterruptedd方法的区别</p><p>Java多线程的中断机制是用内部标识来实现的，调用<strong>Thread.interrupt()来中断一个线程就会设置中断标识为true</strong>。当中断线程调用静态方法Thread.interrupted()来<strong>检查中断状态时，中断状态会被清零</strong>。而<strong>非静态方法isInterrupted()用来查询其它线程的中断状态且不会改变中断状态标识。</strong>简单的说就是任何抛出InterruptedException异常的方法都会将中断状态清零。无论如何，一个线程的中断状态有可能被其它线程调用中断来改变。</p></li><li><p>为什么wait和notify方法要在同步块中调用</p><p>主要是因为Java API强制要求这样做，如果你不这么做，你的代码会抛出IllegalMonitorStateException异常。还有一个原因是为了避免wait和notify之间产生竞态条件。</p></li><li><p>为什么你应该在循环中检查等待条件</p><p>如果不在循环中检查等待条件，程序就会在没有满足结束条件的情况下退出。因此，当一个等待线程醒来时，不能认为它原来的等待状态仍然是有效的，在notify()方法调用之后和等待线程醒来之前这段时间它可能会改变。这就是在循环中使用wait()方法效果更好的原因</p></li><li><p>什么是线程池？ 为什么要使用它？</p><p>创建线程要花费昂贵的资源和时间，如果任务来了才创建线程那么响应时间会变长，而且一个进程能创建的线程数有限。为了避免这些问题，在程序启动的时候就创建若干线程来响应处理，它们被称为线程池，里面的线程叫工作线程。</p></li><li><p>如何写代码来解决生产者消费者问题</p><p>比较低级的办法是用wait和notify来解决这个问题，比较赞的办法是使用 BlockingQueue来实现生产者消费者模型(生产者线程向队列插入元素，消费者线程取出它们)。</p></li><li><p>如何避免死锁 || 死锁程序 || 活锁</p><p>死锁是指两个或两个以上的进程在执行过程中，因争夺资源而造成的一种互相等待的现象。避免死锁最简单的方法就是阻止循环等待条件，将系统中所有的资源设置标志位、排序，规定所有的进程申请资源必须以一定的顺序（升序或降序）做操作来避免死锁。</p><p>活锁的线程或进程的状态是不断改变的。一个现实的活锁例子是两个人在狭小的走廊碰到，两个人都试着避让对方好让彼此通过，但是因为避让的方向都一样导致最后谁都不能通过走廊。简单的说就是，活锁和死锁的主要区别是前者进程的状态可以改变但是却不能继续执行。</p></li><li><p>检测一个线程是否拥有锁</p><p>java.lang.Thread中有一个方法叫holdsLock()，它返回true如果当且仅当当前线程拥有某个具体对象的锁。</p></li><li><p>Java中synchronized 和 ReentrantLock 有什么不同</p><p>Java在过去很长一段时间只能通过synchronized关键字来实现互斥，它有一些缺点。比如你不能扩展锁之外的方法或者块边界，尝试获取锁时不能中途取消等。Java 5 通过Lock接口提供了更复杂的控制来解决这些问题。 ReentrantLock 类实现了 Lock，它拥有与 synchronized 相同的并发性和内存语义且它还具有可扩展性。</p></li><li><p>Thread类中的yield方法有什么作用</p><p>Yield方法可以暂停当前正在执行的线程对象，让其它有相同优先级的线程执行。它是一个静态方法而且只保证当前线程放弃CPU占用，而不能保证使其它线程一定能占用CPU，执行yield()的线程有可能在进入到暂停状态后马上又被执行</p></li><li><p>如果你提交任务时，线程池队列已满。会时发会生什么</p><p>许多程序员会认为该任务会阻塞直到线程池队列有空位。事实上如果一个任务不能被调度执行，那么ThreadPoolExecutor的 submit()方法将会抛出一个RejectedExecutionException异常</p></li><li><p>Java线程池中submit() 和 execute()方法有什么区别</p><p>两个方法都可以向线程池提交任务，<strong>execute()方法的返回类型是void，它定义在Executor接口中</strong>, 而<strong>submit()方法可以返回持有计算结果的Future对象，它定义在ExecutorService接口中</strong>，它扩展了Executor接口，其它线程池类像ThreadPoolExecutor和ScheduledThreadPoolExecutor都有这些方法。</p></li><li><p>Java中的ReadWriteLock是什么</p><p>读写锁是用来提升并发程序性能的锁分离技术的成果。一个ReadWriteLock维护一对关联的锁，一个用于只读操作一个用于写。在没有写线程的情况下一个读锁可能会同时被多个读线程持有；写锁是独占的。它最多支持65535个写锁和65535个读锁。</p></li><li><p>volatile 变量和 atomic 变量有什么不同</p><p>Volatile变量可以确保先行关系，即写操作会发生在后续的读操作之前, 但它并不能保证原子性。例如用volatile修饰count变量那么 count++ 操作就不是原子性的。而AtomicInteger类提供的atomic方法可以让这种操作具有原子性如getAndIncrement()方法会原子性的进行增量操作把当前值加一，其它数据类型和引用变量也可以进行相似操作。</p></li><li><p>写出3条你遵循的多线程最佳实践</p><p>a）给线程命名，这样可以帮助调试。</p><p>b）最小化同步的范围，而不是将整个方法同步，只对关键部分做同步。</p><p>c）如果可以，更偏向于使用 volatile 而不是 synchronized。</p><p>d）使用更高层次的并发工具，而不是使用 wait() 和 notify() 来实现线程间通信，如 BlockingQueue，CountDownLatch 及 Semeaphore。</p><p>e）优先使用并发集合，而不是对集合进行同步。并发集合提供更好的可扩展性。</p><p>f）将线程和任务分离，使用线程池执行器来执行 Runnable 或 Callable</p><p>g）使用线程池</p></li><li><p>Java多线程中调用wait() 和 sleep()方法有什么不同</p><p>Java程序中wait 和 sleep都会造成某种形式的暂停，它们可以满足不同的需要。wait()方法用于线程间通信，如果等待条件为真且其它线程被唤醒时它会释放锁，而sleep()方法仅仅释放CPU资源或者让当前线程停止执行一段时间，但不会释放锁。</p></li><li><p>单例模式的双检锁是什么</p><p>对<code>_instance == null</code>有两次检查，第一次检查没有锁，第二次检查有锁。意图是尽量减少同步成本并提高性能， 只通过锁定关键部分的代码来创建。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title">getInstanceDC</span><span class="params">()</span> </span>&#123;</div><div class="line">  <span class="keyword">if</span> (_instance == <span class="keyword">null</span>) &#123; <span class="comment">// Single Checked</span></div><div class="line">    <span class="keyword">synchronized</span> (Singleton.class) &#123; </div><div class="line">      <span class="keyword">if</span> (_instance == <span class="keyword">null</span>) &#123; <span class="comment">// Double checked</span></div><div class="line">        _instance = <span class="keyword">new</span> Singleton(); </div><div class="line">      &#125; </div><div class="line">    &#125; </div><div class="line">  &#125; </div><div class="line">  <span class="keyword">return</span> _instance; </div><div class="line">&#125;</div></pre></td></tr></table></figure><p>1.5之前当instance为volatile时有问题，在JDK1.5之后，双重检查锁定才能够正常达到单例效果。因为Volatile变量可以确保先行关系，要求写操作要在读操作前。</p></li><li><p>循环打印ABCD</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ABCDPrintThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="comment">// 具体执行打印者</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Printer printer = <span class="keyword">new</span> Printer();</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ABCDPrintThread</span><span class="params">(String name)</span> </span>&#123;</div><div class="line">        <span class="keyword">super</span>(name);</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; <span class="number">5</span>; i++)&#123;</div><div class="line">            printer.print(<span class="keyword">this</span>.getName());</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Printer</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> String targetStr = <span class="string">"A"</span>;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">synchronized</span> <span class="keyword">void</span> <span class="title">print</span><span class="params">(String letter)</span></span>&#123;</div><div class="line"></div><div class="line">        <span class="keyword">while</span> (!letter.equals(targetStr))&#123;</div><div class="line">            <span class="keyword">try</span> &#123;</div><div class="line">                <span class="comment">// 主动释放printer对象锁，同时本线程休眠</span></div><div class="line">                <span class="keyword">this</span>.wait();</div><div class="line">            &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</div><div class="line">                e.printStackTrace();</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        <span class="comment">// 可以打印</span></div><div class="line">        System.out.print(letter);</div><div class="line"></div><div class="line">        <span class="comment">// 打印完A-&gt;B</span></div><div class="line">        targetStr = (<span class="keyword">char</span>)(targetStr.charAt(<span class="number">0</span>) + <span class="number">1</span>) + <span class="string">""</span>;</div><div class="line"></div><div class="line">        <span class="keyword">if</span>(<span class="string">"F"</span>.equals(targetStr)) &#123;</div><div class="line">            targetStr = <span class="string">"A"</span>;</div><div class="line">        &#125;</div><div class="line">        <span class="comment">// 对象锁的唤醒操作，唤醒因为这一条件而等待的所有线程</span></div><div class="line">        <span class="comment">// 假如第一个进入的是C线程，wati()使C线程释放对象锁后进入等待，需要有人来唤醒</span></div><div class="line">        <span class="comment">// sleep()仅是睡眠且不释放锁，时间过后线程可以自动根据竞争机制获取执行机会</span></div><div class="line">        <span class="keyword">this</span>.notifyAll();</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">ABCDPrintThread t1 = <span class="keyword">new</span> ABCDPrintThread(<span class="string">"A"</span>);</div><div class="line">ABCDPrintThread t2 = <span class="keyword">new</span> ABCDPrintThread(<span class="string">"B"</span>);</div><div class="line">t1.start();</div><div class="line">t2.start();</div></pre></td></tr></table></figure></li><li><p>写一个死锁</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div></pre></td><td class="code"><pre><div class="line"><span class="comment">/**</span></div><div class="line"> * 死锁产生:如果线程A持有锁l并且想获得锁m，线程B持有锁m并且想获得锁l，那么这两个线程将永远等待下去，这种情况就是最简单的死锁形式</div><div class="line"> */</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">DeadLock</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object left = <span class="keyword">new</span> Object();</div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Object right = <span class="keyword">new</span> Object();</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">void</span> <span class="title">leftRight</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">        <span class="keyword">synchronized</span> (left) &#123;</div><div class="line">            <span class="comment">// 一定要有"Thread.sleep(2000)"让线程睡一觉，不然一个线程运行了，另一个线程还没有运行，先运行的线程很有可能就已经连续获得两个锁了</span></div><div class="line">            Thread.sleep(<span class="number">2000</span>);</div><div class="line">            <span class="keyword">synchronized</span> (right) &#123;</div><div class="line">                System.out.println(<span class="string">"leftRight end!"</span>);</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">void</span> <span class="title">rightLeft</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>&#123;</div><div class="line">        <span class="keyword">synchronized</span> (right) &#123;</div><div class="line">            Thread.sleep(<span class="number">2000</span>);</div><div class="line">            <span class="keyword">synchronized</span> (left) &#123;</div><div class="line">                System.out.println(<span class="string">"rightLeft end!"</span>);</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Thread1</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> DeadLock dl;</div><div class="line"></div><div class="line">    Thread1(DeadLock dl) &#123;</div><div class="line">        <span class="keyword">this</span>.dl = dl;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            dl.leftRight();</div><div class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">            e.printStackTrace();</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Thread2</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> DeadLock dl;</div><div class="line"></div><div class="line">    Thread2(DeadLock dl) &#123;</div><div class="line">        <span class="keyword">this</span>.dl = dl;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            dl.rightLeft();</div><div class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</div><div class="line">            e.printStackTrace();</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</div><div class="line">    DeadLock dl = <span class="keyword">new</span> DeadLock();</div><div class="line">    Thread1 t1 = <span class="keyword">new</span> Thread1(dl);</div><div class="line">    Thread2 t2 = <span class="keyword">new</span> Thread2(dl);</div><div class="line">    t1.start();</div><div class="line">    t2.start();</div><div class="line">&#125;</div></pre></td></tr></table></figure></li><li><p>用写一段代码来解决生产者-消费者</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div><div class="line">84</div><div class="line">85</div><div class="line">86</div><div class="line">87</div><div class="line">88</div><div class="line">89</div><div class="line">90</div><div class="line">91</div><div class="line">92</div><div class="line">93</div><div class="line">94</div><div class="line">95</div><div class="line">96</div><div class="line">97</div><div class="line">98</div><div class="line">99</div><div class="line">100</div><div class="line">101</div><div class="line">102</div><div class="line">103</div><div class="line">104</div><div class="line">105</div><div class="line">106</div><div class="line">107</div><div class="line">108</div><div class="line">109</div><div class="line">110</div><div class="line">111</div><div class="line">112</div><div class="line">113</div><div class="line">114</div><div class="line">115</div><div class="line">116</div><div class="line">117</div><div class="line">118</div><div class="line">119</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// wait-notify </span></div><div class="line"><span class="comment">/**</span></div><div class="line"> * 生产者</div><div class="line"> */</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Producer</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</div><div class="line">            <span class="keyword">synchronized</span>(queue)&#123;</div><div class="line">                <span class="keyword">while</span>(queue.size() == queueSize)&#123;</div><div class="line">                    <span class="keyword">try</span> &#123;</div><div class="line">                        System.out.println(<span class="string">"队列已满，等待空余的空间"</span>);</div><div class="line">                        queue.wait();</div><div class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</div><div class="line">                        e.printStackTrace();</div><div class="line">                        queue.notify();</div><div class="line">                    &#125;</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                queue.offer(<span class="number">1</span>);   <span class="comment">// 每次插入一个元素</span></div><div class="line">                System.out.println(<span class="string">"向队列取中插入一个元素，队列剩余空间："</span>+(queueSize-queue.size()));</div><div class="line">                queue.notify();</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * 消费者</div><div class="line"> */</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Consumer</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</div><div class="line">            <span class="keyword">synchronized</span> (queue) &#123;</div><div class="line">                <span class="keyword">while</span>(queue.size() ==<span class="number">0</span>)&#123;</div><div class="line">                    <span class="keyword">try</span> &#123;</div><div class="line">                        System.out.println(<span class="string">"队列空，等待数据。。。"</span>);</div><div class="line">                        queue.wait();</div><div class="line">                    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</div><div class="line">                        e.printStackTrace();</div><div class="line">                        queue.notify();</div><div class="line">                    &#125;</div><div class="line">                &#125;</div><div class="line"></div><div class="line">                queue.poll() ;</div><div class="line">                System.out.println(<span class="string">"从队列中取走一个元素，队列中剩余"</span>+queue.size()+<span class="string">"个"</span>);</div><div class="line">                queue.notify();</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// 使用BlockQueue</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProducerConsumerPattern</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span></span>&#123;</div><div class="line">  </div><div class="line">     <span class="comment">//Creating shared object</span></div><div class="line">     BlockingQueue sharedQueue = <span class="keyword">new</span> LinkedBlockingQueue();</div><div class="line"> </div><div class="line">     <span class="comment">//Creating Producer and Consumer Thread</span></div><div class="line">     Thread prodThread = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Producer(sharedQueue));</div><div class="line">     Thread consThread = <span class="keyword">new</span> Thread(<span class="keyword">new</span> Consumer(sharedQueue));</div><div class="line"></div><div class="line">     <span class="comment">//Starting producer and Consumer thread</span></div><div class="line">     prodThread.start();</div><div class="line">     consThread.start();</div><div class="line">    &#125;</div><div class="line"> </div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//Producer Class in java</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Producer</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue sharedQueue;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Producer</span><span class="params">(BlockingQueue sharedQueue)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.sharedQueue = sharedQueue;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">0</span>; i&lt;<span class="number">10</span>; i++)&#123;</div><div class="line">            <span class="keyword">try</span> &#123;</div><div class="line">                System.out.println(<span class="string">"Produced: "</span> + i);</div><div class="line">                sharedQueue.put(i);</div><div class="line">            &#125; <span class="keyword">catch</span> (InterruptedException ex) &#123;</div><div class="line">                Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, <span class="keyword">null</span>, ex);</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//Consumer Class in Java</span></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Consumer</span> <span class="keyword">implements</span> <span class="title">Runnable</span></span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue sharedQueue;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Consumer</span> <span class="params">(BlockingQueue sharedQueue)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.sharedQueue = sharedQueue;</div><div class="line">    &#125;</div><div class="line">  </div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">while</span>(<span class="keyword">true</span>)&#123;</div><div class="line">            <span class="keyword">try</span> &#123;</div><div class="line">                System.out.println(<span class="string">"Consumed: "</span>+ sharedQueue.take());</div><div class="line">            &#125; <span class="keyword">catch</span> (InterruptedException ex) &#123;</div><div class="line">                Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, <span class="keyword">null</span>, ex);</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">  </div><div class="line">  </div><div class="line">&#125;</div></pre></td></tr></table></figure></li><li><p>用 Java 写一个线程安全的单例模式</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 这种方式利用了classloder的机制来保证初始化instance时只有一个线程,这种情况Singleton类被装载了，instance不一定被初始化。</span></div><div class="line"><span class="comment">// 因为SingletonHolder类没有被主动使用，只有显示通过调用getInstance方法时，才会显示装载SingletonHolder类，从而实例化instance。</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span> </span>&#123;</div><div class="line">  <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</span></span>&#123;&#125;</div><div class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> SingletonHolder.INSTANCE;</div><div class="line">  &#125;</div><div class="line">  </div><div class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonHolder</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton INSTANCE = <span class="keyword">new</span> Singleton();</div><div class="line">  &#125;</div><div class="line">&#125; </div><div class="line"></div><div class="line"><span class="comment">// 创建Enum实例是线程安全的，由JVM提供。这种方式是Effective Java作者Josh Bloch 提倡的方式，它不仅能避免多线程同步问题，而且还能防止反序列化重新创建新的对象，可谓是很坚强的壁垒</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Singleton &#123;  </div><div class="line">    INSTANCE;  </div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">whateverMethod</span><span class="params">()</span> </span>&#123;  </div><div class="line">    &#125;  </div><div class="line">&#125;</div></pre></td></tr></table></figure></li></ol><h3 id="集合框架"><a href="#集合框架" class="headerlink" title="集合框架"></a>集合框架</h3><p>与集合相关很多被问到HashMap相关的问题，可以参看之前博客<a href="http://gtwlover.gitee.io/2016/12/25/HashMap%E7%90%86%E8%A7%A3/">HashMap理解</a>。常见面试题：</p><ol><li><p>什么时候用LinkedList，什么时候用ArrayList？</p><p>ArrayList是使用数组实现的list，本质上就是数组。ArrayList中的元素可以通过索引随机获取一个元素。但是如果该数组已满，当添加新元素时需要分配一个新的数组然后将原来数组的元素移动过去，需要O(n)的时间复杂度。添加或删除一个元素需要移动数组中的其他元素。这是ArrayList最大的缺点。</p><p>LinkedList是一个双向链表。因此，当需要获取list中某个元素，需要从头到尾遍历list。另一方面，在链表中添加或删除元素很快，只需要O(1)的时间复杂度。从空间上来说，在链表中一个节点需要两个额外的指针来指向它的previous和next节点。</p><p><strong>总结：</strong></p><p>从<strong>时间复杂度</strong>来说，如果对list增加或删除操作较多，优先用LinkedList；如果查询操作较多，优先用ArrayList。</p><p>从<strong>空间复杂度</strong>来说，LinkedList会占用较多空间。</p></li><li><p>数据与List互转</p><p><code>list.toArray()</code>只能转换对象类型，对基础类型不适用，<code>Arrays.asList()</code>同理。对于基础类型的转换通常是通过循环遍历赋值进行的。因为asList获得的List实际引用的就是数组, <strong>当更新array其中之一时，另一个integerList将自动获得更新</strong>。asList得到的数组是的没有add和remove方法的。因为asList返回的List是Arrays中的内部类,而该类并没有定义add和remove方法，所以这两个方法调用时不会生效。</p></li><li><p>将List转化成Set最简单的方法？</p><p>有两种方法，取决于你怎么要怎么定义两个元素相等。第一种方法是将list放入HashSet里，该方法元素是否相等是通过它们的hashCode()来比较的。如果需要自己定义比较的方法，需要用TreeSet。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line">Set&lt;Integer&gt; set = <span class="keyword">new</span> HashSet&lt;Integer&gt;(list);</div><div class="line"></div><div class="line">Set&lt;Integer&gt; set = <span class="keyword">new</span> TreeSet&lt;Integer&gt;(aComparator);</div><div class="line">set.addAll(list);</div></pre></td></tr></table></figure></li><li><p>如何删除ArrayList中重复的元素？</p><p>如果不关心元素在ArrayList中的顺序，可以将list放入set中来删除重复元素，然后在放回list。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line">Set&lt;Integer&gt; set = <span class="keyword">new</span> HashSet&lt;Integer&gt;(list);</div><div class="line">list.clear();</div><div class="line">list.addAll(set);</div></pre></td></tr></table></figure><p>如果关心元素在ArrayList中的顺序，可以用LinkedHashSet。</p><p>List 是一个有序集合，允许元素重复。它的某些实现可以提供基于下标值的常量访问时间，但是这不是 List 接口保证的。Set 是一个无序集合。</p></li><li><p>poll() 方法和 remove() 方法的区别？</p><p>poll() 和 remove() 都是从队列中取出一个元素，但是 poll() 在获取元素失败的时候会返回空，但是 remove() 失败的时候会抛出异常。</p></li><li><p>Java 中 LinkedHashMap 和 PriorityQueue 的区别是什么？</p><p>PriorityQueue 保证最高或者最低优先级的的元素总是在队列头部，但是 LinkedHashMap 维持的顺序是元素插入的顺序。当遍历一个 PriorityQueue 时，没有任何顺序保证，但是 LinkedHashMap 课保证遍历顺序是元素插入的顺序。</p></li><li><p>ArrayList 与 LinkedList 的不区别？</p><p>最明显的区别是 ArrrayList 底层的数据结构是数组，支持随机访问，而 LinkedList 的底层数据结构书链表，不支持随机访问。使用下标访问一个元素，ArrayList 的时间复杂度是 O(1)，而 LinkedList 是 O(n)。</p></li><li><p>用哪两种方式来实现集合的排序？</p><p>可以使用有序集合，如 TreeSet 或 TreeMap，你也可以使用有顺序的的集合，如 list，然后通过 Collections.sort() 来排序。</p></li><li><p>Java 中怎么打印数组？</p><p>可以使用 Arrays.toString() 和 Arrays.deepToString() 方法来打印数组。由于数组没有实现 toString() 方法，所以如果将数组传递给 System.out.println(array) 方法，将无法打印出数组的内容，但是 <code>System.out.println(Arrays.deepToString(array));</code> 可以打印每个元素。</p></li><li><p>Java 中的 LinkedList 是单向链表还是双向链表？</p><p>是双向链表，可以检查 JDK 的源码。</p></li><li><p>Java 中的 TreeMap 是采用什么树实现的？</p><p>Java 中的 TreeMap 是使用红黑树实现的。</p></li><li><p>Hashtable 与 HashMap 有什么不同之处？</p><p>Java中Hashtable和HashMap之间的相似之处：</p><p>a） Hashtable和 HashMap都实现了java.util.Map接口。<br>b） Hashtable和 HashMap都是基于哈希的集合，并且以哈希为原则起作用。<br>c） Hashtable和 HashMap都可以在put和get方法中提供恒定的时间性能，如果对象分布在一个数据桶中。</p><p>尽管如此相似，Hashtable和HashMap之间存在一些区别，它们完全分开了它们，我们来看看：</p><p>a）Hashtable和HashMap之间的第一个和最显着的不同之处在于HashMap不是线程安全的，而Hashtable是线程安全的集合。<br>b）Hashtable和HashMap之间的第二个重要区别是性能，Hashtable 是同步的，比较慢，但 HashMap 没有同步策略，所以会更快。<br>c）Hashtable 不允许有个空的 key，但是 HashMap 允许出现一个 null key。<br>d）Hashtable与HashMap的第三个区别是Hashtable是过时的类，你应该使用ConcurrentHashMap代替Java中的Hashtable(Hashtable 是 JDK 1 遗留下来的类，而 HashMap 是后来增加的)。</p></li><li><p>自动扩容</p><p>Vector：线程安全，但速度慢<br>　　　　底层数据结构是数组结构<br>　　　　加载因子为1：即当 元素个数 超过 容量长度 时，进行扩容<br>　　　　扩容增量：原容量的 1倍<br>　　　　　　如 Vector的容量为10，一次扩容后是容量为20</p><p>ArrayList：线程不安全，查询速度快<br>　　　　底层数据结构是数组结构<br>　　　　扩容增量：原容量的 0.5倍+1<br>　　　　　　如 ArrayList的容量为10，一次扩容后是容量为16</p><p>HashMap：默认初始容量为16<br>　　　　　加载因子为0.75：即当元素个数超过容量长度的0.75倍时，进行扩容<br>　　　　　扩容增量：原容量的 1 倍<br>　　　　　如 HashSet的容量为16，一次扩容后是容量为32</p><p>StringBuilder：默认初始容量为16<br>　　　　　字符串长度 count+str.length() &lt;= (value*2+2)则按value*2+2长度扩容，并且value=value*2+2<br>　　　　　若 count+str.length() &gt; (value*2+2)，则按count+str.length()长度扩容，并且value=count+str.length()</p></li><li><p>写一段代码在遍历 ArrayList 时移除一个元素？</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">for</span>(Iterator&lt;String&gt; itr = list.iterator(); itr.hasNext();)&#123;</div><div class="line">    String phone = itr.next();</div><div class="line">    <span class="keyword">if</span>(phone.startsWith(<span class="string">"iPhone"</span>))&#123;]</div><div class="line">        itr.remove(); <span class="comment">// right call</span></div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line">java8:</div><div class="line">list.removeIf(phone -&gt; phone.startsWith(<span class="string">"iPhone"</span>));</div></pre></td></tr></table></figure><p>该问题的关键在于面试者使用的是 ArrayList 的 remove() 还是 Iterator 的 remove()方法。这有一段示例代码，是使用正确的方式来实现在遍历的过程中移除元素，而不会出现 ConcurrentModificationException 异常的示例代码。</p></li><li><p>我们能自己写一个容器类，然后使用 for-each 循环吗？</p><p>可以，你可以写一个自己的容器类。如果你想使用 Java 中增强的循环来遍历，你只需要实现 Iterable 接口。如果你实现 Collection 接口，默认就具有该属性。</p></li><li><p>ArrayList 和 HashMap 的默认大小是多数？</p><p>在 Java 7 中，ArrayList 的默认大小是 10 个元素，HashMap 的默认大小是16个元素（必须是2的幂）。这就是 Java 7 中 ArrayList 和 HashMap 类的代码片段：</p></li><li><p>两个相同的对象会有不同的的 hash code 吗？</p><p>不能，根据 hashcode 的规定，这是不可能的。</p></li><li><p>有没有可能两个不相等的对象有有相同的 hashcode？</p><p>有可能，两个不相等的对象可能会有相同的 hashcode 值，这就是为什么在 hashmap 中会有冲突。相等 hashcode 值的规定只是说如果两个对象相等，必须有相同的hashcode 值，但是没有关于不相等对象的任何规定。</p></li><li><p>我们可以在 hashcode() 中使用随机数字吗？</p><p>不行，因为对象的 hashcode 值必须是相同的。参见答案获取更多关于 Java 中重写 hashCode() 方法的知识。</p></li><li><p>Java 中，Comparator 与 Comparable 有什么不同？</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Person</span> <span class="keyword">implements</span> <span class="title">Comparable</span>&lt;<span class="title">Person</span>&gt;</span>&#123;</div><div class="line">  <span class="comment">/**</span></div><div class="line">     * 实现Comparable&lt;String&gt;的接口，即重写compareTo&lt;T t&gt;函数。</div><div class="line">     * 这里是通过“person的名字”进行比较的</div><div class="line">     */</div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compareTo</span><span class="params">(Person person)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> name.compareTo(person.name);</div><div class="line">        <span class="comment">//return this.name - person.name;</span></div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">/**</span></div><div class="line"> * AscAgeComparator比较器</div><div class="line"> * 它是“Person的age的升序比较器”</div><div class="line"> */</div><div class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">AscAgeComparator</span> <span class="keyword">implements</span> <span class="title">Comparator</span>&lt;<span class="title">Person</span>&gt; </span>&#123;</div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compare</span><span class="params">(Person p1, Person p2)</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> p1.getAge() - p2.getAge();</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// 排序</span></div><div class="line">Collections.sort(personList);</div><div class="line">Collections.sort(personList, <span class="keyword">new</span> AscAgeComparator());</div></pre></td></tr></table></figure><p>Comparable 接口用于定义对象的<strong>自然顺序</strong>，而 comparator 通常用于定义用户<strong>定制的顺序</strong>。Comparable 总是只有一个，但是可以有多个 comparator 来定义对象的顺序。</p></li><li><p>为什么在重写 equals 方法的时候需要重写 hashCode 方法？</p><p>因为有强制的规范指定需要同时重写 hashcode 与 equal 是方法，许多容器类，如 HashMap、HashSet 都依赖于 hashcode 与 equals 的规定。</p></li><li><p>说出几点 Java 中使用 Collections 的最佳实践</p><p>a）使用正确的集合类，例如，如果不需要同步列表，使用 ArrayList 而不是 Vector。<br>b）<strong>优先使用并发集合，而不是对集合进行同步</strong>。并发集合提供更好的可扩展性。<br>c）<strong>使用接口代表访问集合</strong>，如使用List存储 ArrayList，使用 Map 存储 HashMap 等等。<br>d）<strong>使用迭代器来循环集合</strong>。<br>e）<strong>使用集合的时候使用泛型</strong>。</p></li></ol><h3 id="IO与NIO"><a href="#IO与NIO" class="headerlink" title="IO与NIO"></a>IO与NIO</h3><h2 id="数据库"><a href="#数据库" class="headerlink" title="数据库"></a>数据库</h2><h3 id="MySQL"><a href="#MySQL" class="headerlink" title="MySQL"></a>MySQL</h3><p>参考之前博客<a href="http://gtwlover.gitee.io/2016/11/15/MySQL%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E7%82%B9/">MySQL相关知识点</a></p><p>如果问的比较深点，涉及到大量数据的分库分表怎么处理，包括主键生成策略等，参考<a href="http://gtwlover.gitee.io/2017/06/21/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8/">数据库分库分表(Sharding)</a></p><h3 id="Redis"><a href="#Redis" class="headerlink" title="Redis"></a>Redis</h3><p>参考之前博客<a href="http://gtwlover.gitee.io/2016/12/26/Redis%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E7%82%B9/">Redis相关知识点</a></p><h2 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a>JVM</h2><h3 id="GC相关"><a href="#GC相关" class="headerlink" title="GC相关"></a>GC相关</h3><p>有关GC的算法，参看之前博客<a href="http://gtwlover.gitee.io/2017/05/05/JVM-%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%90%86%E8%A7%A3/">JVM-垃圾回收理解</a>。</p><h2 id="设计模式"><a href="#设计模式" class="headerlink" title="设计模式"></a>设计模式</h2><p>关于设计原则，参看之前博客<a href="http://gtwlover.gitee.io/2017/05/07/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-SOLID%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99/">设计模式-SOLID设计原则</a>。具体的设计模式，参看<a href="http://gtwlover.gitee.io/2017/05/08/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">设计模式-创建型模式</a>、<a href="http://gtwlover.gitee.io/2017/05/09/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F/">设计模式-结构型模式</a>、<a href="http://gtwlover.gitee.io/2017/05/10/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F-%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F/">设计模式-行为型模式</a></p><p>相关面试题：</p><ol><li><p>如何创建线程安全的单例</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 这种方式利用了classloder的机制来保证初始化instance时只有一个线程,这种情况Singleton类被装载了，instance不一定被初始化。</span></div><div class="line"><span class="comment">// 因为SingletonHolder类没有被主动使用，只有显示通过调用getInstance方法时，才会显示装载SingletonHolder类，从而实例化instance。</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Singleton</span> </span>&#123;</div><div class="line">  <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</span></span>&#123;&#125;</div><div class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>&#123;</div><div class="line">    <span class="keyword">return</span> SingletonHolder.INSTANCE;</div><div class="line">  &#125;</div><div class="line">  </div><div class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonHolder</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton INSTANCE = <span class="keyword">new</span> Singleton();</div><div class="line">  &#125;</div><div class="line">&#125; </div><div class="line"></div><div class="line"><span class="comment">// 创建Enum实例是线程安全的，由JVM提供。这种方式是Effective Java作者Josh Bloch 提倡的方式，它不仅能避免多线程同步问题，而且还能防止反序列化重新创建新的对象，可谓是很坚强的壁垒</span></div><div class="line"><span class="keyword">public</span> <span class="keyword">enum</span> Singleton &#123;  </div><div class="line">    INSTANCE;  </div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">whateverMethod</span><span class="params">()</span> </span>&#123;  </div><div class="line">    &#125;  </div><div class="line">&#125;</div></pre></td></tr></table></figure></li><li><p>工厂与抽象工厂区别</p><p>工厂方法模式： 一个抽象产品类，可以派生出多个具体产品类。<br>抽象工厂模式： 多个抽象产品类，每个抽象产品类可以派生出多个具体产品类，每个具体工厂类可以创建多个具体产品类的实例。<br>区别： 工厂方法模式只有一个抽象产品类，而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例，而抽象工厂模式可以创建多个。</p></li><li><p>适配器模式和装饰器模式有什么区别？</p><p>虽然适配器模式和装饰器模式的结构类似，但是每种模式的出现意图不同。适配器模式被用于桥接两个接口，而装饰模式的目的是在不修改类的情况下给类增加新的功能。</p></li><li><p>适配器模式和代理模式之前有什么不同？</p><p>这个问题与前面的类似，适配器模式和代理模式的区别在于他们的意图不同。由于适配器模式和代理模式都是封装真正执行动作的类，因此结构是一致的，但是适配器模式用于接口之间的转换，而代理模式则是增加一个额外的中间层，以便支持分配、控制或智能访问。</p></li><li><p>什么是模板方法模式？</p><p>模板方法提供算法的框架，你可以自己去配置或定义步骤。例如，你可以将排序算法看做是一个模板。它定义了排序的步骤，但是具体的比较，可以使用 Comparable 或者其语言中类似东西，具体策略由你去配置。列出算法概要的方法就是众所周知的模板方法。</p></li><li><p>什么时候使用访问者模式？</p><p>访问者模式用于解决在类的继承层次上增加操作，但是不直接与之关联。这种模式采用双派发的形式来增加中间层。</p></li><li><p>什么时候使用组合模式？</p><p>组合模式使用树结构来展示部分与整体继承关系。它允许客户端采用统一的形式来对待单个对象和对象容器。当你想要展示对象这种部分与整体的继承关系时采用组合模式。</p></li><li><p>继承和组合之间有什么不同？</p><p>虽然两种都可以实现代码复用，但是组合比继承共灵活，因为组合允许你在运行时选择不同的实现。用组合实现的代码也比继承测试起来更加简单。</p></li><li><p>什么时候在Java中使用策略设计模式？</p><p>策略模式对于实现一组相关算法非常有用，例如压缩算法，过滤策略等。策略设计模式允许您创建Context类，它使用Strategy实现类来应用业务规则。这种模式遵循开放的封闭设计原则，在Java中非常有用。来自JDK本身的Strategy模式的一个例子是Collections.sort()方法和Comparator接口，它是策略接口，并定义了比较对象的策略。由于这种模式，我们不需要修改sort()方法（修改关闭）来比较任何对象，同时我们可以实现Comparator接口来定义新的比较策略（开放扩展）。</p></li><li><p>什么是Java中的Observer设计模式？什么时候在Java中使用Observer模式？<br>这是最常见的Java设计模式访问问题之一。观察者模式基于通知，有两种对象主题和观察者。每当主体状态发生变化时，观察员将收到通知。</p></li><li><p>Java中的策略与状态设计模式之间的区别？<br>策略和状态模式都具有相同的结构。如果你看这两个模式的UML类图，它们看起来完全相同，但是意图是完全不同的。状态设计模式用于定义和管理对象状态，而策略模式用于定义一组可互换算法，让客户端选择其中之一。所以策略模式是一个客户驱动的模式，而对象可以管理那里的状态本身。</p></li><li><p>什么是Java中的装饰器模式？你能举一个装饰模式吗？<br>Decorator模式是另一种流行的java设计模式问题，因为它在java.io包中的使用很多，这是很常见的。BufferedReader和BufferedWriter是Java中装饰器模式的好例子。</p></li><li><p>何时在Java中使用组合设计模式？您以前在项目中使用过吗？<br>这个设计模式问题是在Java面试中提出的，不仅仅是要检查复合模式的熟悉程度，还要考虑候选人是否具有现实生活中的经验。<em>复合图案</em>也是一个核心的Java设计模式，它允许您以类似的方式对待整个对象和零件对象进行处理。处理Composite或单个对象的客户端代码并不区分它们，因为Composite类也可以实现与单独部分相同的界面。JDK的Composite Pattern的一个很好的例子是JPanel类，它是Component和Container。当在JPanel上调用paint（）方法时，它内部称为各个组件的paint（） 方法，并让它们自己绘制。在这个设计模式面试问题的第二部分，要真实的，如果你使用然后说是的，否则说你熟悉的概念，并用自己的。顺便提一句，给你一个例子，从你的项目创造更好的印象。</p></li><li><p>什么是Java中的Singleton模式？<br>Java中的Singleton模式是一种只允许在整个应用程序中使用Singleton类的一个实例的模式。java.lang.Runtime是Java中Singleton模式的好例子。</p></li><li><p>在Java中使用Template方法设计模式？<br>模板模式是另一个流行的核心Java设计模式访问问题。我已经看到它在现实生活项目中出现了很多次。模板模式概述了模板方法的一种算法，并让子类实现各个步骤。重点要提到的是，在回答这个问题的时候，模板方法应该是final的，所以子类不能覆盖和改变算法的步骤，但是同一个人的步骤应该是抽象的，所以子类可以实现它们。</p></li><li><p>什么是Java中的Factory模式？使用静态工厂方法创建对象有什么优点？<br>Java中的工厂模式是许多Java面试中创建的Java设计模式和最喜爱的。通过提供静态工厂方法来创建对象的工厂模式。提供工厂方法有很多优点，例如缓存不可变对象，容易引入新对象等。</p></li><li><p>Java中的装饰器和代理模式之间的区别？<br>另一个棘手的Java设计模式问题在这里是装饰器和代理实现他们装饰或封装的对象的接口。正如我所说，许多Java设计模式可以具有相似或完全相同的结构，但在意图上有所不同。装饰器模式用于在已创建的对象上实现功能，而代理模式用于控制对对象的访问。Decorator和Proxy设计模式之间的另一个区别是，Decorator不会创建对象，而是在其构造函数中获取对象，而Proxy实际上创建对象。</p></li><li><p>何时在依赖注入模式中使用Setter和Constructor Injection？<br>使用Setter注入来提供对象的可选依赖关系，同时使用构造函数注入来提供对象的强制依赖关系，否则它不能工作。这个问题与依赖注入设计模式有关，主要是在Spring框架的上下文中提出的，现在它已经成为开发Java应用程序的标准。由于Spring提供了IOC容器，它还为您提供了使用setter方法或构造函数指定依赖关系的方法。</p></li><li><p>何时在Java中使用适配器模式？你以前在项目中使用过吗？*<br>当需要使用不兼容的接口进行两个类工作时，请使用适配器模式。适配器模式也可用于封装第三方代码，以便您的应用程序仅依赖于适配器，当第三方代码更改或您移动到另一个第三方库时，它可以适应自身。顺便说一下，这个Java设计模式问题也可以通过提供实际场景来询问。</p></li><li><p>什么是Java中的Builder设计模式？什么时候使用Builder模式？<br>当需要构造一个对象时需要多个属性，有些属性是可选 的，有些是必须的。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BuilderPatternExample</span> </span>&#123;</div><div class="line">  </div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String args[])</span> </span>&#123;</div><div class="line">      </div><div class="line">        <span class="comment">//Creating object using Builder pattern in java</span></div><div class="line">        Cake whiteCake = <span class="keyword">new</span> Cake.Builder().sugar(<span class="number">1</span>).butter(<span class="number">0.5</span>).  eggs(<span class="number">2</span>).vanila(<span class="number">2</span>).flour(<span class="number">1.5</span>). bakingpowder(<span class="number">0.75</span>).milk(<span class="number">0.5</span>).build();</div><div class="line">      </div><div class="line">        <span class="comment">//Cake is ready to eat :)</span></div><div class="line">        System.out.println(whiteCake);</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Cake</span> </span>&#123;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">double</span> sugar;   <span class="comment">//cup</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">double</span> butter;  <span class="comment">//cup</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> eggs;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> vanila;     <span class="comment">//spoon</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">double</span> flour;   <span class="comment">//cup</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">double</span> bakingpowder; <span class="comment">//spoon</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">double</span> milk;  <span class="comment">//cup</span></div><div class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">int</span> cherry;</div><div class="line"></div><div class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Builder</span> </span>&#123;</div><div class="line"></div><div class="line">        <span class="keyword">private</span> <span class="keyword">double</span> sugar;   <span class="comment">//cup</span></div><div class="line">        <span class="keyword">private</span> <span class="keyword">double</span> butter;  <span class="comment">//cup</span></div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> eggs;</div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> vanila;     <span class="comment">//spoon</span></div><div class="line">        <span class="keyword">private</span> <span class="keyword">double</span> flour;   <span class="comment">//cup</span></div><div class="line">        <span class="keyword">private</span> <span class="keyword">double</span> bakingpowder; <span class="comment">//spoon</span></div><div class="line">        <span class="keyword">private</span> <span class="keyword">double</span> milk;  <span class="comment">//cup</span></div><div class="line">        <span class="keyword">private</span> <span class="keyword">int</span> cherry;</div><div class="line"></div><div class="line">        <span class="comment">//builder methods for setting property</span></div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">sugar</span><span class="params">(<span class="keyword">double</span> cup)</span></span>&#123;<span class="keyword">this</span>.sugar = cup; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">butter</span><span class="params">(<span class="keyword">double</span> cup)</span></span>&#123;<span class="keyword">this</span>.butter = cup; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">eggs</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;<span class="keyword">this</span>.eggs = number; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">vanila</span><span class="params">(<span class="keyword">int</span> spoon)</span></span>&#123;<span class="keyword">this</span>.vanila = spoon; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">flour</span><span class="params">(<span class="keyword">double</span> cup)</span></span>&#123;<span class="keyword">this</span>.flour = cup; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">bakingpowder</span><span class="params">(<span class="keyword">double</span> spoon)</span></span>&#123;<span class="keyword">this</span>.sugar = spoon; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">milk</span><span class="params">(<span class="keyword">double</span> cup)</span></span>&#123;<span class="keyword">this</span>.milk = cup; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">        <span class="function"><span class="keyword">public</span> Builder <span class="title">cherry</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;<span class="keyword">this</span>.cherry = number; <span class="keyword">return</span> <span class="keyword">this</span>; &#125;</div><div class="line">      </div><div class="line">      </div><div class="line">        <span class="comment">//return fully build object</span></div><div class="line">        <span class="function"><span class="keyword">public</span> Cake <span class="title">build</span><span class="params">()</span> </span>&#123;</div><div class="line">            <span class="keyword">return</span> <span class="keyword">new</span> Cake(<span class="keyword">this</span>);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="comment">//private constructor to enforce object creation through builder</span></div><div class="line">    <span class="function"><span class="keyword">private</span> <span class="title">Cake</span><span class="params">(Builder builder)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.sugar = builder.sugar;</div><div class="line">        <span class="keyword">this</span>.butter = builder.butter;</div><div class="line">        <span class="keyword">this</span>.eggs = builder.eggs;</div><div class="line">        <span class="keyword">this</span>.vanila = builder.vanila;</div><div class="line">        <span class="keyword">this</span>.flour = builder.flour;</div><div class="line">        <span class="keyword">this</span>.bakingpowder = builder.bakingpowder;</div><div class="line">        <span class="keyword">this</span>.milk = builder.milk;</div><div class="line">        <span class="keyword">this</span>.cherry = builder.cherry;       </div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> <span class="string">"Cake&#123;"</span> + <span class="string">"sugar="</span> + sugar + <span class="string">", butter="</span> + butter + <span class="string">", eggs="</span> + eggs + <span class="string">", vanila="</span> + vanila + <span class="string">", flour="</span> + flour + <span class="string">", bakingpowder="</span> + bakingpowder + <span class="string">", milk="</span> + milk + <span class="string">", cherry="</span> + cherry + <span class="string">'&#125;'</span>;</div><div class="line"></div><div class="line">    &#125; </div><div class="line">  </div><div class="line">&#125;</div><div class="line"></div><div class="line">Output:</div><div class="line">Cake&#123;sugar=<span class="number">0.75</span>, butter=<span class="number">0.5</span>, eggs=<span class="number">2</span>, vanila=<span class="number">2</span>, flour=<span class="number">1.5</span>, bakingpowder=<span class="number">0.0</span>, milk=<span class="number">0.5</span>, cherry=<span class="number">0</span>&#125;</div></pre></td></tr></table></figure></li></ol><h2 id="算法"><a href="#算法" class="headerlink" title="算法"></a>算法</h2><p>面试中会经常问到排序相关的算法，参看之前博客<a href="http://gtwlover.gitee.io/2017/03/04/%E5%85%AB%E5%A4%A7%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/">八大排序算法</a>。面试中遇到的其他相关算法类题目：</p><p>1.检测数组中重复元素</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">checkDuplicateUsingAdd</span><span class="params">(String[] input)</span> </span>&#123;</div><div class="line">  Set tempSet = <span class="keyword">new</span> HashSet();</div><div class="line">  <span class="keyword">for</span> (String str : input) &#123;</div><div class="line">    <span class="keyword">if</span> (!tempSet.add(str)) &#123;</div><div class="line">        <span class="comment">// 需要重复元素，可返回str</span></div><div class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</div><div class="line">    &#125;</div><div class="line">  &#125;</div><div class="line">  <span class="keyword">return</span> <span class="keyword">false</span>;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>2.反转字符串</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="comment">// 1.利用StringBuilder</span></div><div class="line">String reverseStr = <span class="keyword">new</span> StringBuffer(str).reverse().toString();</div><div class="line"></div><div class="line"><span class="comment">// 2.递归</span></div><div class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title">reverseRecursively</span><span class="params">(String str)</span> </span>&#123;</div><div class="line"></div><div class="line">  <span class="comment">//base case to handle one char string and empty string</span></div><div class="line">  <span class="keyword">if</span> (str.length() &lt; <span class="number">2</span>) &#123;</div><div class="line">    <span class="keyword">return</span> str;</div><div class="line">  &#125;</div><div class="line"></div><div class="line">  <span class="keyword">return</span> reverseRecursively(str.substring(<span class="number">1</span>)) + str.charAt(<span class="number">0</span>);</div><div class="line"></div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">// 3.数字反转</span></div><div class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">reverse</span><span class="params">(<span class="keyword">int</span> number)</span></span>&#123;</div><div class="line">  <span class="keyword">int</span> reverse = <span class="number">0</span>;</div><div class="line"></div><div class="line">  <span class="keyword">while</span>(number != <span class="number">0</span>)&#123;</div><div class="line">    reverse = reverse*<span class="number">10</span> + number%<span class="number">10</span>; </div><div class="line">    number = number/<span class="number">10</span>;</div><div class="line">  &#125;</div><div class="line"></div><div class="line">  <span class="keyword">return</span> reverse;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>3.怎么检查一个字符串只包含数字？ — 利用正则表达式</p><p>4.Java 中，怎么获取一个文件中单词出现的最高频率？</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Count</span> </span>&#123;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</div><div class="line">        <span class="keyword">try</span> &#123;</div><div class="line">            <span class="comment">// 读取文件内容到String中</span></div><div class="line">            BufferedReader br = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> FileReader(<span class="string">"F:\\EnglishReading.txt"</span>));</div><div class="line">            String s;</div><div class="line">            StringBuffer sb = <span class="keyword">new</span> StringBuffer();</div><div class="line">            <span class="keyword">while</span> ((s = br.readLine()) != <span class="keyword">null</span>) &#123;</div><div class="line">                sb.append(s);</div><div class="line">            &#125;</div><div class="line">          </div><div class="line">            Map&lt;String,Integer&gt; map = <span class="keyword">new</span> HashMap&lt;String, Integer&gt;();</div><div class="line">            StringTokenizer st = <span class="keyword">new</span> StringTokenizer(sb.toString(),<span class="string">",.! \n"</span>);<span class="comment">//按(“，”，“.”，“！”，“空格”，“回车”)分割</span></div><div class="line">            <span class="keyword">while</span> (st.hasMoreTokens()) &#123;</div><div class="line">                String letter = st.nextToken();</div><div class="line">                <span class="keyword">int</span> count;</div><div class="line">                <span class="keyword">if</span> (map.get(letter) == <span class="keyword">null</span>) &#123;</div><div class="line">                    count = <span class="number">1</span>;</div><div class="line">                &#125; <span class="keyword">else</span> &#123;</div><div class="line">                    count = map.get(letter).intValue() + <span class="number">1</span>;</div><div class="line">                &#125;</div><div class="line">                <span class="comment">// 将单词次数放入到Map中</span></div><div class="line">                map.put(letter,count);</div><div class="line">            &#125;</div><div class="line">          </div><div class="line">            Set&lt;WordEntity&gt; set = <span class="keyword">new</span> TreeSet&lt;WordEntity&gt;();</div><div class="line">            <span class="comment">// 将map中内容放入WordEntity</span></div><div class="line">            <span class="keyword">for</span> (String key : map.keySet()) &#123;</div><div class="line">                set.add(<span class="keyword">new</span> WordEntity(key,map.get(key)));</div><div class="line">            &#125;</div><div class="line">          </div><div class="line">            <span class="comment">// 控制输出前十名来</span></div><div class="line">            <span class="keyword">int</span> count = <span class="number">1</span>;</div><div class="line">            <span class="keyword">for</span> (Iterator it = set.iterator(); it.hasNext(); ) &#123;</div><div class="line">                WordEntity w = it.next();</div><div class="line">                System.out.println(<span class="string">"第"</span> + count + <span class="string">"名为单词:"</span> + w.getKey() + <span class="string">" 出现的次数为： "</span></div><div class="line">                        + w.getCount());</div><div class="line">                <span class="keyword">if</span> (count == <span class="number">10</span>)<span class="comment">// 当输出10个后跳出循环</span></div><div class="line">                    <span class="keyword">break</span>;</div><div class="line">                count++;</div><div class="line">            &#125;</div><div class="line">        &#125; <span class="keyword">catch</span> (FileNotFoundException e) &#123;</div><div class="line">            System.out.println(<span class="string">"文件未找到~！"</span>);</div><div class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</div><div class="line">            System.out.println(<span class="string">"文件读异常~！"</span>);</div><div class="line">        &#125;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="comment">//WordEntity类</span></div><div class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WordEntity</span> <span class="keyword">implements</span> <span class="title">Comparable</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> String key;</div><div class="line">    <span class="keyword">private</span> Integer count;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="title">WordEntity</span> <span class="params">(String key, Integer count)</span> </span>&#123;</div><div class="line">        <span class="keyword">this</span>.key = key;</div><div class="line">        <span class="keyword">this</span>.count = count;</div><div class="line">    &#125;</div><div class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">compareTo</span><span class="params">(WordEntity o)</span> </span>&#123;</div><div class="line">        <span class="keyword">int</span> cmp = count.intValue() - o.count.intValue();</div><div class="line">        <span class="keyword">return</span> (cmp == <span class="number">0</span> ? key.compareTo(o.key) : -cmp);</div><div class="line">        <span class="comment">//只需在这儿加一个负号就可以决定是升序还是降序排列  -cmp降序排列，cmp升序排列</span></div><div class="line">        <span class="comment">//因为TreeSet会调用WorkForMap的compareTo方法来决定自己的排序</span></div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="meta">@Override</span></div><div class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> key + <span class="string">" 出现的次数为："</span> + count;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getKey</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> key;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="function"><span class="keyword">public</span> Integer <span class="title">getCount</span><span class="params">()</span> </span>&#123;</div><div class="line">        <span class="keyword">return</span> count;</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure><p>5.Java 中，怎么打印出一个字符串的所有排列？ — 利用递归</p><p>6.Java 中，怎样才能打印出数组中的重复元素？</p><p>7.在没有使用临时变量的情况如何交换两个整数变量的值？</p><figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">int</span> a=<span class="number">10</span>; <span class="comment">// a = 1010</span></div><div class="line"><span class="keyword">int</span> b=<span class="number">12</span>; <span class="comment">// b = 1100</span></div><div class="line"><span class="comment">// 异或运算能够使数据中的某些位翻转，其他位不变。这就意味着任意一个数与任意一个给定的值连续异或两次，值不变。即：a^b^b=a</span></div><div class="line">a=a^b; <span class="comment">// 得到翻转值</span></div><div class="line">b=a^b; <span class="comment">// 相当于a^b^b，得到之前a的值</span></div><div class="line">a=a^b; <span class="comment">// 此时b为之前a，相当于a^b^a，得到之前b的值</span></div><div class="line">System.out.println(a + <span class="string">"--"</span> + b);</div></pre></td></tr></table></figure><h2 id="框架"><a href="#框架" class="headerlink" title="框架"></a>框架</h2><h3 id="Spring"><a href="#Spring" class="headerlink" title="Spring"></a>Spring</h3><p>先注意Spring事务传播级别，上图一张</p><p><img src="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/Spring%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E7%BA%A7%E5%88%AB.png" alt="Spring事务传播级别"></p><p>关于<code>@Transactional</code>的详解，参考<a href="http://gtwlover.gitee.io/2017/10/14/%E9%80%8F%E5%BD%BB%E6%8E%8C%E6%8F%A1Spring%E4%B8%AD-Transactional%E7%9A%84%E4%BD%BF%E7%94%A8/">透彻掌握Spring中@Transactional的使用</a>与<a href="http://gtwlover.gitee.io/2017/10/12/%E5%85%B3%E4%BA%8E-Transactional%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB/">关于@Transactional源码解读</a></p><p>具体一些关于Spring一些讲解，参考<a href="http://gtwlover.gitee.io/categories/Spring/">Spring模块</a></p><ol><li><p>什么是Spring</p><p>Spring 是一个开源框架，是为了解决企业应用程序开发复杂性而创建的,Spring提供了IOC和AOP,很好的降低了代码的耦合性。</p></li><li><p>什么是IOC</p><p>IOC即 Inversion of control，将使用new操作符创建对象的形式转换为使用容器或框架。一般维护一个XML文件，或者使用注解，来配置我们的组件，服务，所有类及其属性。</p><p>我们只需要申明需要什么，组件或容器就会为我们创建所需的服务对象(通过 JavaBean 的属性（例如 setter 方法）分配依赖性;依赖以构造函数的形式提供，不以 JavaBean 属性的形式公开)。这个概念被称为依赖注入，因为所有的依赖对象（资源）都被框架注入到容器中。</p><p>反转控制是依赖注入的实现之一，优点：构造函数和设置器依赖注入减少耦合，依赖注入允许用模拟对象替换实际对象，通过编写使用模拟对象的简单JUnit测试来提高可测试性。</p></li><li><p>什么是AOP</p><p>通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 主要功能有：日志记录、性能统计、安全控制、事务处理、异常处理等。</p><p>AOP的核心构造是将多个类影响到可重用模块的行为。AOP是一种编程技术，允许开发人员模块化横切关注点，跨越典型的责任划分，如<strong>日志记录和事务管理。</strong>Spring AOP中，方面使用的是带有注释的普通班或普通班实施@Aspect注解。</p></li><li><p>什么是Advice</p><p>是切面的实现，在连接点将advice插入应用程序，advice类型有before,after,around。<br>AOP是补充OOPS的另一个流行的编程概念。join point是我们可以应用一个aspect在代码中的机会。在Spring AOP中，连接点总是表示方法执行。<br>point cut是匹配连接点的断言，一个切点是定义在什么连接点上应该应用advice的东西</p></li><li><p>依赖注入与工厂模式的区别</p><p>依赖注入是一种设计模式，对象的依赖性由第三方框架或容器注入，而不是由Object本身创建,主要有两种类型的依赖注入：构造器注入和Setter注入;工厂模式依赖是通过客户端自己获取。</p><p>在依赖注入中，客户端类没有关于如何创建和管理依赖关系的线索。它只知道依赖关系。大多数依赖关系是通过框架注入的，例如，bean类没有任何硬编码依赖关系，因为这些依赖关系是由IOC容器（如Spring）注入的。</p><p>工厂模式增加了对象，工厂和依赖关系之间的耦合。对象不仅需要依赖对象正常工作，还需要一个Factory对象。在依赖注入的情况下，Object只知道依赖关系，它不了解容器或工厂的任何内容。</p><p>与工厂模式相比，依赖注入的一个缺点是需要一个容器和配置来注入依赖项，如果使用工厂设计模式，则不需要它</p><p>工厂和依赖注入之间的主要区别在于，在工厂的情况下，户端类负责调用工厂类的getInstance()来创建对象实例，这也意味着客户端类与工厂直接耦合，依赖类仍然依赖于工厂，这是一种新的依赖形式，而DI完全依赖于依赖关系。这意味着依赖注入为工厂设计模式提供了更好的去耦。</p></li><li><p>什么时候使用Setter注入和构造函数注入</p><p>当对象依赖关系不是可选的，它们必须使用它们的依赖关系初始化，如果初始化或依赖的顺序非常重要，可以使用构造函数注入，因为在基于Setter的注入中，不能强加任何顺序。当依赖项是可选的时候使用setter注入。</p></li><li><p>Bean的生命周期</p><p>Spring框架基于IOC容器，所以Spring bean放在在IOC容器中，Spring bean就是普通的java对象（POJO）。它在容器内的生命周期：</p><p>容器查看配置文件中的bean定义—&gt;<br>使用反射容器创建对象，如果在bean定义中定义了任何属性，那么它也将被设置—&gt;<br>①如果bean实现BeanNameAware接口，工厂调用setBeanName()传递bean的ID<br>②如果bean实现了BeanFactoryAware接口，工厂调用setBeanFactory()，传递一个本身的实例<br>③如果有任何与BeanPostProcessor的与Bean关联，他们的post-ProcessBeforeInitialization()方法会在 bean的属性设置之前被调用<br>④如果为bean 指定了一个特殊的init()方法，那么它将被调用<br>⑤如果Bean类实现了DisposableBean接口，那么当Application不再需要bean引用时，将调用destroy()方法<br>⑥如果配置文件中的Bean定义包含“destroy-method”属性，那么Bean类中相应的方法定义将被调用。</p></li><li><p>BeanFactory是什么</p><p>BeanFactory是基于IOC的工厂模式，用于在应用程序配置和实际代码的依赖之间做出明确的分离。XmlBeanFactory是我们在项目使用的bean工厂的实现方式之一，用于创建我们的XML文件中定义的bean实例。</p></li><li><p>BeanFactory与ApplicationContext区别</p><p>| Application Context | Bean Factory |<br>| —————————————- | ————————- |<br>| 这里我们可以有多个配置文件 | 在这只有一个配置文件或.xml文件 |<br>| 应用程序上下文可以将事件发布到作为监听器注册的bean | 不支持 |<br>| 支持国际化（I18N）消息 | 不是 |<br>| 支持应用程序生命周期事件和验证 | 不支持 |<br>| 支持许多企业服务，如JNDI访问，EJB集成，远程处理 | 不支持 |</p></li><li><p>Spring有哪些模块</p><p>组成 Spring 框架的每个模块（或组件）都可以单独存在，或者与其他一个或多个模块联合实现。</p><ul><li><strong>核心容器</strong>：核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 <code>BeanFactory</code>，它是工厂模式的实现。<code>BeanFactory</code> 使用<em>控制反转</em> （IOC） 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。</li><li><strong>Spring 上下文</strong>：Spring 上下文是一个配置文件，向 Spring 框架提供上下文信息。Spring 上下文包括企业服务，例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。</li><li><strong>Spring AOP</strong>：通过配置管理特性，Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以，可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP，不用依赖 EJB 组件，就可以将声明性事务管理集成到应用程序中。</li><li><strong>Spring DAO</strong>：JDBC DAO 抽象层提供了有意义的异常层次结构，可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理，并且极大地降低了需要编写的异常代码数量（例如打开和关闭连接）。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。</li><li><strong>Spring ORM</strong>：Spring 框架插入了若干个 ORM 框架，从而提供了 ORM 的对象关系工具，其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。</li><li><strong>Spring Web 模块</strong>：Web 上下文模块建立在应用程序上下文模块之上，为基于 Web 的应用程序提供了上下文。所以，Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。</li><li><strong>Spring MVC 框架</strong>：MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口，MVC 框架变成为高度可配置的，MVC 容纳了大量视图技术，其中包括 JSP、Velocity、Tiles、iText 和 POI。</li></ul><p><img src="http://gtw.oss-cn-shanghai.aliyuncs.com/Spring/SpringFramework.png" alt="SpringFramework"></p><p>​</p></li><li><p>单例和原型bean有什么区别</p><p><strong>Singleton：</strong>指Spring IOC容器中对象为单例形式，只有一个。<br><strong>Prototype</strong>：单个bean定义指向任何数量的对象实例的。</p><p>在spring框架中bean，bean标签中有一个名为’singleton’的属性，默认情况下，它设置为true。如果指定为true，则bean为singleton；如果设置为false，则该bean将变为prototype。</p></li><li><p>Spring支持什么类型的事务管理</p><p>支持两种类型的事务管理：程序化事务管理、声明式事务管理。</p></li><li><p>Spring中的setter和constructor注入的区别</p><p>①使用setter方法比在配置文件中通过构造函数注入的可读性通常要高，通过读取Spring XML配置文件知道set哪些依赖。在构造函数注入过程中，由于它使用索引来注入依赖关系，所以它不像setter注入一样可读，需要引用代码来查找哪个索引对应于哪个属性。<br>②setter注入的缺点之一 是它不能保证某些依赖关系是否被注入，这意味着可能拥有不完全依赖的对象，而构造函数注入此时不允许构建对象，直到依赖项准备就绪。<br>③setter注射的另一个缺点是安全。通过使用setter注入，可以重写依赖,这在构造函数注入中是不可能的，因为每次调用构造函数时，对象已经被创建了。<br>使用setter:构造对象是参数过长，或是A与B对象循环依赖；使用constructor：创建对象时必须使用所有依赖关系，来注入强制性依赖项</p></li><li><p>Spring用到的设计模式</p><p>工厂方法模式<br>Spring中提供了FactoryBean接口，用于创建各种不同的Bean。</p><p>模板方法模式<br>Spring针对JDBC,JMS,JPA等规范，都提供了相应的模板方法类，如JdbcTemplate,JmsTemplate, JpaTemplate。 例如JdbcTemplate,它提供了很多常用的增加，删除，查询，修改方法模板。而JMSTemplate则提供了对于消息的发送，接收方法等。</p><p>代理模式<br>Spring中AOP，事务等都大量运用了代理模式。<br>Spring中提供了一种事件监听机制，即ApplicationListener，可以实现Spring容器内的事件监听。可以参考<a href="http://docs.spring.io/spring/docs/3.2.15.RELEASE/spring-framework-reference/htmlsingle/#context-functionality-events" target="_blank" rel="external">这里</a>主要是以下两个接口： 发布消息和监听消息</p><p>单例模式<br>Spring默认的创建Bean的作用域就是单例，即每个Spring容器中只存在一个该类的实例。可以通过@Scope(“prototype”)来修改成prototype模式,prototype在设计模式中叫做原型模式，实际上，Spring中对于@Scope(“prototype”)标记的Bean的处理的确是原型模式。</p><p>原型模式<br>原型模式是创建型模式的一种,其特点在于通过“复制”一个已经存在的实例来返回新的实例,而不是新建实例。被复制的实例就是我们所称的“原型”，这个原型是可定制的。 原型模式多用于创建复杂的或者耗时的实例，因为这种情况下，复制一个已经存在的实例使程序运行更高效；或者创建值相等，只是命名不一样的同类数据。<br>Spring中，如果一个类被标记为”prototype”,每一次请求（将其注入到另一个bean中，或者以程序的方式调用容器的getBean()方法）都会产生一个新的bean实例。 但是,Spring不能对一个prototype Bean的整个生命周期负责，容器在初始化、配置、装饰或者是装配完一个prototype实例后，将它交给客户端，随后就对该prototype实例不闻不问了。不管何种作用域，容器都会调用所有对象的初始化生命周期回调方法，而对prototype而言，任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源，都是客户端代码的职责。</p><p>职责链模式<br>在SpringMVC中，我们会经常使用一些拦截器(<code>HandlerInterceptor</code>),当存在多个拦截器的时候，所有的拦截器就构成了一条拦截器链。SpringMVC中使用<code>HandlerExecutionChain</code>类来将所有的拦截器组装在一起。​</p></li></ol><h3 id="MyBatis"><a href="#MyBatis" class="headerlink" title="MyBatis"></a>MyBatis</h3><p>相关被问到的是一二级缓存，参看之前博客<a href="http://gtwlover.gitee.io/2016/11/16/MyBatis%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%8E%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98/">MyBatis一级缓存与二级缓存</a>。</p><p>Mybatis框架和Hibernate框架比较：</p><ol><li>“全自动化”的Hibernate对数据库结构提供了完整的封装和全套映射机制。</li><li>“半自动化”的Mybatis提供的ORM机制，对业务逻辑实现人员而言，面对的是纯粹的Java对象。</li><li>Hibernate会自动生成SQL语句，而MyBatis不会在运行期间自动生成SQL语句执行。</li></ol><h2 id="Git"><a href="#Git" class="headerlink" title="Git"></a>Git</h2><ul><li>git 方便的branch在哪里，团队多人如何协作？冲突了怎么办？如何进行发布控制？</li><li>经典的master-发布、develop-主开发、hotfix-不过修复如何避免代码不经过验证上线？</li><li>如何在github上面与他人一起协作，star-fork-pull request是怎样的流程？</li><li>误操作撤销</li></ul><h2 id="锁相关"><a href="#锁相关" class="headerlink" title="锁相关"></a>锁相关</h2><h3 id="乐观锁（-Optimistic-Locking）"><a href="#乐观锁（-Optimistic-Locking）" class="headerlink" title="乐观锁（ Optimistic Locking）"></a>乐观锁（ Optimistic Locking）</h3><p>相对悲观锁而言，乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现，以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销，特别是对长事务而言，这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。乐观锁，大多是基于数据版本（ Version ）记录机制实现。何谓数据版本？即为数据增加一个版本标识，在基于数据库表的版本解决方案中，一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时，将此版本号一同读出，之后更新时，对此版本号加一。此时，将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对，如果提交的数据版本号大于数据库表当前版本号，则予以更新，否则认为是过期数据。</p><h3 id="悲观锁（Pessimistic-Lock）"><a href="#悲观锁（Pessimistic-Lock）" class="headerlink" title="悲观锁（Pessimistic Lock）"></a>悲观锁（Pessimistic Lock）</h3><p>正如其名，具有强烈的独占和排他特性。它指的是对数据被外界（包括本系统当前的其他事务，以及来自外部系统的事务处理）修改持保守态度，因此，在整个数据处理过程中，将数据处于锁定状态。悲观锁的实现，往往依靠数据库提供的锁机制（也只有数据库层提供的锁机制才能真正保证数据访问的排他性，否则，即使在本系统中实现了加锁机制，也无法保证外部系统不会修改数据）。</p><p><strong>简而言之：</strong><br>悲观锁：假定会发生并发冲突，屏蔽一切可能违反数据完整性的操作。<br>乐观锁：假设不会发生并发冲突，只在提交操作时检查是否违反数据完整性。<br>乐观锁不能解决脏读的问题。</p><h3 id="Java中的乐观锁和悲观锁"><a href="#Java中的乐观锁和悲观锁" class="headerlink" title="Java中的乐观锁和悲观锁"></a>Java中的乐观锁和悲观锁</h3><p>cpu是时分复用的，也就是把cpu的时间片，分配给不同的thread/process轮流执行，时间片与时间片之间，需要进行cpu切换，也就是会发生进程的切换。切换涉及到清空寄存器，缓存数据。然后重新加载新的thread所需数据。当一个线程被挂起时，加入到阻塞队列，在一定的时间或条件下，在通过notify()，notifyAll()唤醒回来。在某个资源不可用的时候，就将cpu让出，把当前等待线程切换为阻塞状态。等到资源(比如一个共享数据）可用了，那么就将线程唤醒，让他进入runnable状态等待cpu调度。这就是典型的悲观锁的实现。独占锁是一种悲观锁，synchronized就是一种独占锁，它假设最坏的情况，并且只有在确保其它线程不会造成干扰的情况下执行，会导致其它所有需要锁的线程挂起，等待持有锁的线程释放锁。<br>但是，由于在进程挂起和恢复执行过程中存在着很大的开销。当一个线程正在等待锁时，它不能做任何事（<strong>阻塞</strong>），所以悲观锁有很大的缺点。举个例子，如果一个线程需要某个资源，但是这个资源的占用时间很短，当线程第一次抢占这个资源时，可能这个资源被占用，如果此时挂起这个线程，可能立刻就发现资源可用，然后又需要花费很长的时间重新抢占锁，时间代价就会非常的高。<br>所以就有了乐观锁的概念，他的核心思路就是，每次不加锁而是假设没有冲突而去完成某项操作，如果因为冲突失败就重试，直到成功为止。在上面的例子中，某个线程可以不让出cpu,而是一直while循环，如果失败就重试，直到成功为止。所以，当数据争用不严重时，乐观锁效果更好。比如CAS就是一种乐观锁思想的应用。</p><p>JDK1.5中引入了底层的支持，在int、long和对象的引用等类型上都公开了CAS的操作，并且JVM把它们编译为底层硬件提供的最有效的方法，在运行CAS的平台上，运行时把它们编译为相应的机器指令。<br>在java.util.concurrent.atomic包下面的所有的原子变量类型中，比如AtomicInteger，都使用了这些底层的JVM支持为数字类型的引用类型提供一种高效的CAS操作。<br>在CAS操作中，会出现ABA问题。就是如果V的值先由A变成B，再由B变成A，那么仍然认为是发生了变化，并需要重新执行算法中的步骤。有简单的解决方案：不是更新某个引用的值，而是更新两个值，包括一个引用和一个版本号，即使这个值由A变为B，然后为变为A，版本号也是不同的。AtomicStampedReference和AtomicMarkableReference支持在两个变量上执行原子的条件更新。AtomicStampedReference更新一个“对象-引用”二元组，通过在引用上加上“版本号”，从而避免ABA问题，AtomicMarkableReference将更新一个“对象引用-布尔值”的二元组。</p></div><div><div><div style="text-align:center;margin-top:35px;color:#ccc;font-size:14px">------------------------------------本文结束<i class="fa fa-paw"></i>感谢阅读------------------------------------</div></div></div><div><div style="padding:10px 0;margin:20px auto;width:90%;text-align:center"><div>坚持技术分享，你的支持将鼓励我继续创作！</div> <button id="rewardButton" disable="enable" onclick='var qr=document.getElementById("QR");"none"===qr.style.display?qr.style.display="block":qr.style.display="none"'> <span>打赏</span></button><div id="QR" style="display:none"><div id="wechat" style="display:inline-block"> <img id="wechat_qr" src="http://gtw.oss-cn-shanghai.aliyuncs.com/reward.jpg" alt="脱毛大白兔 微信支付"><p>微信支付</p></div></div></div></div><footer class="post-footer"><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/2017/05/10/DesignPattern-Behavioral/" rel="next" title="设计模式-行为型模式"><i class="fa fa-chevron-left"></i> 设计模式-行为型模式</a></div><span class="post-nav-divider"></span><div class="post-nav-prev post-nav-item"> <a href="/2017/06/21/Sharding/" rel="prev" title="数据库分库分表(Sharding)">数据库分库分表(Sharding)<i class="fa fa-chevron-right"></i></a></div></div></footer></div></article><div class="post-spread"></div></div></div><div class="comments" id="comments"><div id="gitment-container"></div></div></div><div class="sidebar-toggle"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span><span class="sidebar-toggle-line sidebar-toggle-line-middle"></span><span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div><aside id="sidebar" class="sidebar"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap"> 文章目录</li><li class="sidebar-nav-overview" data-target="site-overview-wrap"> 站点概览</li></ul><section class="site-overview-wrap sidebar-panel"><div class="site-overview"><div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person"> <img class="site-author-image" itemprop="image" src="http://gtw.oss-cn-shanghai.aliyuncs.com/myself/my3.jpeg?x-oss-process=style/zoom" alt="脱毛大白兔"><p class="site-author-name" itemprop="name">脱毛大白兔</p><p class="site-description motion-element" itemprop="description">一路哼哼唧唧，潇潇洒洒，飘飘扬扬地走下去...</p></div><nav class="site-state motion-element"><div class="site-state-item site-state-posts"> <a href="/archives/"><span class="site-state-item-count">51</span> <span class="site-state-item-name">日志</span></a></div><div class="site-state-item site-state-categories"> <a href="/categories/index.html"><span class="site-state-item-count">9</span> <span class="site-state-item-name">分类</span></a></div><div class="site-state-item site-state-tags"> <a href="/tags/index.html"><span class="site-state-item-count">10</span> <span class="site-state-item-name">标签</span></a></div></nav><div id="music163player" style="margin-bottom:-25px"><iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width="2800" height="86" src="//music.163.com/outchain/player?type=2&id=2408566&auto=0&height=66"></iframe></div><div class="links-of-author motion-element"><span class="links-of-author-item"><a href="https://github.com/gaotingwang" target="_blank" title="GitHub"><i class="fa fa-fw fa-github"></i> GitHub</a></span><span class="links-of-author-item"><a href="mailto:code_butcher@sina.com" target="_blank" title="E-Mail"><i class="fa fa-fw fa-envelope"></i> E-Mail</a></span></div><div class="links-of-blogroll motion-element links-of-blogroll-block"><div class="links-of-blogroll-title"><i class="fa fa-fw fa-link"></i> 友情链接</div><ul class="links-of-blogroll-list"><li class="links-of-blogroll-item"> <a href="http://www.ruanyifeng.com/blog/" title="阮一峰日志" target="_blank">阮一峰日志</a></li><li class="links-of-blogroll-item"> <a href="http://blog.didispace.com/" title="程序员DD博客" target="_blank">程序员DD博客</a></li></ul></div></div></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#Java相关"><span class="nav-number">1.</span> <span class="nav-text">Java相关</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Java基础"><span class="nav-number">1.1.</span> <span class="nav-text">Java基础</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#多线程"><span class="nav-number">1.2.</span> <span class="nav-text">多线程</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#集合框架"><span class="nav-number">1.3.</span> <span class="nav-text">集合框架</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#IO与NIO"><span class="nav-number">1.4.</span> <span class="nav-text">IO与NIO</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数据库"><span class="nav-number">2.</span> <span class="nav-text">数据库</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#MySQL"><span class="nav-number">2.1.</span> <span class="nav-text">MySQL</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Redis"><span class="nav-number">2.2.</span> <span class="nav-text">Redis</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#JVM"><span class="nav-number">3.</span> <span class="nav-text">JVM</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#GC相关"><span class="nav-number">3.1.</span> <span class="nav-text">GC相关</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#设计模式"><span class="nav-number">4.</span> <span class="nav-text">设计模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#算法"><span class="nav-number">5.</span> <span class="nav-text">算法</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#框架"><span class="nav-number">6.</span> <span class="nav-text">框架</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Spring"><span class="nav-number">6.1.</span> <span class="nav-text">Spring</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#MyBatis"><span class="nav-number">6.2.</span> <span class="nav-text">MyBatis</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Git"><span class="nav-number">7.</span> <span class="nav-text">Git</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#锁相关"><span class="nav-number">8.</span> <span class="nav-text">锁相关</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#乐观锁（-Optimistic-Locking）"><span class="nav-number">8.1.</span> <span class="nav-text">乐观锁（ Optimistic Locking）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#悲观锁（Pessimistic-Lock）"><span class="nav-number">8.2.</span> <span class="nav-text">悲观锁（Pessimistic Lock）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Java中的乐观锁和悲观锁"><span class="nav-number">8.3.</span> <span class="nav-text">Java中的乐观锁和悲观锁</span></a></li></ol></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer"><div class="footer-inner"><div class="copyright">&copy; 2015 &mdash; <span itemprop="copyrightYear">2018</span><span class="with-love"><i class="fa fa-user"></i></span> <span class="author" itemprop="copyrightHolder">脱毛大白兔</span></div></div></footer><div class="back-to-top"><i class="fa fa-arrow-up"></i> <span id="scrollpercent"><span>0</span>%</span></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script><script type="text/javascript" src="/lib/three/three.min.js"></script><script type="text/javascript" src="/lib/three/three-waves.min.js"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/affix.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script><link rel="stylesheet" href="https://aimingoo.github.io/gitmint/style/default.css"><script src="https://aimingoo.github.io/gitmint/dist/gitmint.browser.js"></script><style>a.gitment-editor-footer-tip{display:none}.gitment-container.gitment-footer-container{display:none}</style><script type="text/javascript">function renderGitment(){new Gitmint({id:window.location.pathname,owner:"gaotingwang",repo:"blog-comments",lang:"en",oauth:{client_secret:"9e283c98b95c605df85e3c7ab94459861b670c6d",client_id:"0c1815a490b171e0c853"}}).render("gitment-container")}renderGitment()</script><link rel="stylesheet" href="/lib/algolia-instant-search/instantsearch.min.css"><script src="/lib/algolia-instant-search/instantsearch.min.js"></script><script src="/js/src/algolia-search.js?v=5.1.4"></script><script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script><script>AV.initialize("d1eLP5bbeDvg09d922elyLBr-gzGzoHsz","MCTjBqQOcTRrfvljPi77Fzsm")</script><script>function showTime(e){var t=new AV.Query(e),n=[],o=$(".leancloud_visitors");o.each(function(){n.push($(this).attr("id").trim())}),t.containedIn("url",n),t.find().done(function(e){var t=".leancloud-visitors-count";if(0!==e.length){for(var i=0;i<e.length;i++){var s=e[i],r=s.get("url"),l=s.get("time"),c=document.getElementById(r);$(c).find(t).text(l)}for(i=0;i<n.length;i++){r=n[i],c=document.getElementById(r);var u=$(c).find(t);""==u.text()&&u.text(0)}}else o.find(t).text(0)}).fail(function(e,t){console.log("Error: "+t.code+" "+t.message)})}function addCount(e){var t=$(".leancloud_visitors"),n=t.attr("id").trim(),o=t.attr("data-flag-title").trim(),i=new AV.Query(e);i.equalTo("url",n),i.find({success:function(t){if(t.length>0){var i=t[0];i.fetchWhenSave(!0),i.increment("time"),i.save(null,{success:function(e){$(document.getElementById(n)).find(".leancloud-visitors-count").text(e.get("time"))},error:function(e,t){console.log("Failed to save Visitor num, with error message: "+t.message)}})}else{var s=new e,r=new AV.ACL;r.setPublicReadAccess(!0),r.setPublicWriteAccess(!0),s.setACL(r),s.set("title",o),s.set("url",n),s.set("time",1),s.save(null,{success:function(e){$(document.getElementById(n)).find(".leancloud-visitors-count").text(e.get("time"))},error:function(e,t){console.log("Failed to create")}})}},error:function(e){console.log("Error:"+e.code+" "+e.message)}})}$(function(){var e=AV.Object.extend("Counter");1==$(".leancloud_visitors").length?addCount(e):$(".post-title-link").length>1&&showTime(e)})</script><script>!function(){var t=document.createElement("script"),e=window.location.protocol.split(":")[0];t.src="https"===e?"https://zz.bdstatic.com/linksubmit/push.js":"http://push.zhanzhang.baidu.com/push.js";var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(t,s)}()</script><script type="text/x-mathjax-config">
  MathJax.Hub.Config("MathJax config");
</script><script type="text/x-mathjax-config">
  MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
      all[i].SourceElement().parentNode.className += ' has-jax';
    }
  });
</script><script type="text/javascript" src="custom_mathjax_source"></script></body></html>